#include "RenderProcess.h"
#include "../Scene/GameScene.h"
#include "../../Render/RenderState.h"


RenderProcess::~RenderProcess()
{
	for (auto& bufferIter : mProxyBufferMap)
	{
		bufferIter.second->ClearProcess();
	}
	mProxyBufferMap.clear();

	for (auto& textureIter : mProxyTextureMap)
	{
		textureIter.second->ClearProcess();
	}
	mProxyTextureMap.clear();

	for (auto& pipelineIter : mProxyPipelineMap)
	{
		pipelineIter.second->ClearProcess();
	}
	mProxyPipelineMap.clear();

	for (auto& renderPassIter : mProxyRenderPassMap)
	{
		renderPassIter.second->ClearProcess();
	}
	mProxyRenderPassMap.clear();

	for (auto& frameBufferIter : mProxyFrameBufferMap)
	{
		frameBufferIter.second->ClearProcess();
	}
	mProxyFrameBufferMap.clear();

	for (auto& descriptorIter : mProxyDescriptorMap)
	{
		descriptorIter.second->ClearProcess();
	}
	mProxyDescriptorMap.clear();

	for (auto& accelerationStructureIter : mProxyAccelerationStructureMap)
	{
		accelerationStructureIter.second->ClearProcess();
	}
	mProxyAccelerationStructureMap.clear();

	for (auto& accelerationStructureGeometryIter : mProxyAccelerationStructureGeometryMap)
	{
		accelerationStructureGeometryIter.second->ClearProcess();
	}
	mProxyAccelerationStructureGeometryMap.clear();

	for (auto& samplerIter : mProxySamplerMap)
	{
		samplerIter.second->ClearProcess();
	}
	mProxySamplerMap.clear();

	for (auto& commandBufferIter : mProxyCommandBufferMap)
	{
		commandBufferIter.second->ClearProcess();
	}
	mProxyCommandBufferMap.clear();

	for (auto& fenceIter : mProxyFenceMap)
	{
		fenceIter.second->ClearProcess();
	}
	mProxyFenceMap.clear();

	for (auto& semaphoreIter : mProxySemaphoreMap)
	{
		semaphoreIter.second->ClearProcess();
	}
	mProxySemaphoreMap.clear();
}

RefCountPtr<RHIBuffer> RenderProcess::GetBuffer(const std::string& name) const
{
	auto bufferIter = mProxyBufferMap.find(name);
	assert(bufferIter != mProxyBufferMap.end());
	return RefCountPtr<RHIBuffer>(bufferIter->second);
}

RefCountPtr<RHITexture> RenderProcess::GetTexture(const std::string& name) const
{
	auto textureIter = mProxyTextureMap.find(name);
	assert(textureIter != mProxyTextureMap.end());
	return RefCountPtr<RHITexture>(textureIter->second);
}

RefCountPtr<RHIPipeline> RenderProcess::GetPipeline(const std::string& name) const
{
	auto pipelineIter = mProxyPipelineMap.find(name);
	assert(pipelineIter != mProxyPipelineMap.end());
	return RefCountPtr<RHIPipeline>(pipelineIter->second);
}

RefCountPtr<RHIRenderPass> RenderProcess::GetRenderPass(const std::string& name) const
{
	auto renderPassIter = mProxyRenderPassMap.find(name);
	assert(renderPassIter != mProxyRenderPassMap.end());
	return RefCountPtr<RHIRenderPass>(renderPassIter->second);
}

RefCountPtr<RHIFrameBuffer> RenderProcess::GetFrameBuffer(const std::string& name) const
{
	auto frameBufferIter = mProxyFrameBufferMap.find(name);
	assert(frameBufferIter != mProxyFrameBufferMap.end());
	return RefCountPtr<RHIFrameBuffer>(frameBufferIter->second);
}

RefCountPtr<RHIDescriptor> RenderProcess::GetDescriptor(const std::string& name) const
{
	auto descriptorIter = mProxyDescriptorMap.find(name);
	assert(descriptorIter != mProxyDescriptorMap.end());
	return RefCountPtr<RHIDescriptor>(descriptorIter->second);
}

RefCountPtr<AccelerationStructure> RenderProcess::GetAccelerationStructure(const std::string& name) const
{
	auto accelerationStructureIter = mProxyAccelerationStructureMap.find(name);
	assert(accelerationStructureIter != mProxyAccelerationStructureMap.end());
	return RefCountPtr<AccelerationStructure>(accelerationStructureIter->second);
}

RefCountPtr<AccelerationStructureGeometry> RenderProcess::GetAccelerationStructureGeometry(const std::string& name) const
{
	auto accelerationStructureGeometryIter = mProxyAccelerationStructureGeometryMap.find(name);
	assert(accelerationStructureGeometryIter != mProxyAccelerationStructureGeometryMap.end());
	return RefCountPtr<AccelerationStructureGeometry>(accelerationStructureGeometryIter->second);
}

RefCountPtr<RHISampler> RenderProcess::GetSampler(const std::string& name) const
{
	auto samplerIter = mProxySamplerMap.find(name);
	assert(samplerIter != mProxySamplerMap.end());
	return RefCountPtr<RHISampler>(samplerIter->second);
}

RefCountPtr<RHICommandBuffer> RenderProcess::GetCommandBuffer(const std::string& name) const
{
	auto commandBufferIter = mProxyCommandBufferMap.find(name);
	assert(commandBufferIter != mProxyCommandBufferMap.end());
	return RefCountPtr<RHICommandBuffer>(commandBufferIter->second);
}

RefCountPtr<RHIFence> RenderProcess::GetFence(const std::string& name) const
{
	auto fenceIter = mProxyFenceMap.find(name);
	assert(fenceIter != mProxyFenceMap.end());
	return RefCountPtr<RHIFence>(fenceIter->second);
}

RefCountPtr<RHISemaphore> RenderProcess::GetSemaphore(const std::string& name) const
{
	auto semaphoreIter = mProxySemaphoreMap.find(name);
	assert(semaphoreIter != mProxySemaphoreMap.end());
	return RefCountPtr<RHISemaphore>(semaphoreIter->second);
}

void RenderProcess::AddBuffer(const std::string& name, RHIBuffer* buffer)
{
	auto bufferIter = mProxyBufferMap.find(name);
	if (bufferIter != mProxyBufferMap.end())
	{
		// mProxyBufferMap.at(name) = buffer;
		bufferIter->second = buffer;
	}
	else
	{
		mProxyBufferMap.insert({ name, buffer });
	}
	buffer->SetProcessAndName(this, name);
}

void RenderProcess::RemoveBuffer(const std::string& name, RHIBuffer* buffer)
{
	auto bufferIter = mProxyBufferMap.find(name);
	if (bufferIter == mProxyBufferMap.end())
		return;
	if (bufferIter->second != buffer)
		return;
	mProxyBufferMap.erase(bufferIter);
}

void RenderProcess::AddTexture(const std::string& name, RHITexture* texture)
{
	auto textureIter = mProxyTextureMap.find(name);
	if (textureIter != mProxyTextureMap.end())
	{
		textureIter->second = texture;
	}
	else
	{
		mProxyTextureMap.insert({ name, texture });
	}
	texture->SetProcessAndName(this, name);
}

void RenderProcess::RemoveTexture(const std::string& name, RHITexture* texture)
{
	auto textureIter = mProxyTextureMap.find(name);
	if (textureIter == mProxyTextureMap.end())
		return;
	if (textureIter->second != texture)
		return;
	mProxyTextureMap.erase(textureIter);
}

void RenderProcess::AddPipeline(const std::string& name, RHIPipeline* pipeline)
{
	auto pipelineIter = mProxyPipelineMap.find(name);
	if (pipelineIter != mProxyPipelineMap.end())
	{
		pipelineIter->second = pipeline;
	}
	else
	{
		mProxyPipelineMap.insert({ name, pipeline });
	}
	pipeline->SetProcessAndName(this, name);
}

void RenderProcess::RemovePipeline(const std::string& name, RHIPipeline* pipeline)
{
	auto pipelineIter = mProxyPipelineMap.find(name);
	if (pipelineIter == mProxyPipelineMap.end())
		return;
	if (pipelineIter->second != pipeline)
		return;
	mProxyPipelineMap.erase(pipelineIter);
}

void RenderProcess::AddRenderPass(const std::string& name, RHIRenderPass* renderPass)
{
	auto renderPassIter = mProxyRenderPassMap.find(name);
	if (renderPassIter != mProxyRenderPassMap.end())
	{
		renderPassIter->second = renderPass;
	}
	else
	{
		mProxyRenderPassMap.insert({ name, renderPass });
	}
	renderPass->SetProcessAndName(this, name);
}

void RenderProcess::RemoveRenderPass(const std::string& name, RHIRenderPass* renderPass)
{
	auto renderPassIter = mProxyRenderPassMap.find(name);
	if (renderPassIter == mProxyRenderPassMap.end())
		return;
	if (renderPassIter->second != renderPass)
		return;
	mProxyRenderPassMap.erase(renderPassIter);
}

void RenderProcess::AddFrameBuffer(const std::string& name, RHIFrameBuffer* frameBuffer)
{
	auto frameBufferIter = mProxyFrameBufferMap.find(name);
	if (frameBufferIter != mProxyFrameBufferMap.end())
	{
		frameBufferIter->second = frameBuffer;
	}
	else
	{
		mProxyFrameBufferMap.insert({ name, frameBuffer });
	}
	frameBuffer->SetProcessAndName(this, name);
}

void RenderProcess::RemoveFrameBuffer(const std::string& name, RHIFrameBuffer* frameBuffer)
{
	auto frameBufferIter = mProxyFrameBufferMap.find(name);
	if (frameBufferIter == mProxyFrameBufferMap.end())
		return;
	if (frameBufferIter->second != frameBuffer)
		return;
	mProxyFrameBufferMap.erase(frameBufferIter);
}

void RenderProcess::AddDescriptor(const std::string& name, RHIDescriptor* descriptor)
{
	auto descriptorIter = mProxyDescriptorMap.find(name);
	if (descriptorIter != mProxyDescriptorMap.end())
	{
		descriptorIter->second = descriptor;
	}
	else
	{
		mProxyDescriptorMap.insert({ name, descriptor });
	}
	descriptor->SetProcessAndName(this, name);
}

void RenderProcess::RemoveDescriptor(const std::string& name, RHIDescriptor* descriptor)
{
	auto descriptorIter = mProxyDescriptorMap.find(name);
	if (descriptorIter == mProxyDescriptorMap.end())
		return;
	if (descriptorIter->second != descriptor)
		return;
	mProxyDescriptorMap.erase(descriptorIter);
}

void RenderProcess::AddAccelerationStructure(const std::string& name, AccelerationStructure* accelerationStructure)
{
	auto accelerationStructureIter = mProxyAccelerationStructureMap.find(name);
	if (accelerationStructureIter != mProxyAccelerationStructureMap.end())
	{
		accelerationStructureIter->second = accelerationStructure;
	}
	else
	{
		mProxyAccelerationStructureMap.insert({ name, accelerationStructure });
	}
	accelerationStructure->SetProcessAndName(this, name);
}

void RenderProcess::RemoveAccelerationStructure(const std::string& name, AccelerationStructure* accelerationStructure)
{
	auto accelerationStructureIter = mProxyAccelerationStructureMap.find(name);
	if (accelerationStructureIter == mProxyAccelerationStructureMap.end())
		return;
	if (accelerationStructureIter->second != accelerationStructure)
		return;
	mProxyAccelerationStructureMap.erase(accelerationStructureIter);
}

void RenderProcess::AddAccelerationStructureGeometry(const std::string& name, AccelerationStructureGeometry* accelerationStructureGeometry)
{
	auto accelerationStructureGeometryIter = mProxyAccelerationStructureGeometryMap.find(name);
	if (accelerationStructureGeometryIter != mProxyAccelerationStructureGeometryMap.end())
	{
		accelerationStructureGeometryIter->second = accelerationStructureGeometry;
	}
	else
	{
		mProxyAccelerationStructureGeometryMap.insert({ name, accelerationStructureGeometry });
	}
	accelerationStructureGeometry->SetProcessAndName(this, name);
}

void RenderProcess::RemoveAccelerationStructureGeometry(const std::string& name, AccelerationStructureGeometry* accelerationStructureGeometry)
{
	auto accelerationStructureGeometryIter = mProxyAccelerationStructureGeometryMap.find(name);
	if (accelerationStructureGeometryIter == mProxyAccelerationStructureGeometryMap.end())
		return;
	if (accelerationStructureGeometryIter->second != accelerationStructureGeometry)
		return;
	mProxyAccelerationStructureGeometryMap.erase(accelerationStructureGeometryIter);
}

void RenderProcess::AddSampler(const std::string& name, RHISampler* sampler)
{
	auto samplerIter = mProxySamplerMap.find(name);
	if (samplerIter != mProxySamplerMap.end())
	{
		samplerIter->second = sampler;
	}
	else
	{
		mProxySamplerMap.insert({ name, sampler });
	}
	sampler->SetProcessAndName(this, name);
}

void RenderProcess::RemoveSampler(const std::string& name, RHISampler* sampler)
{
	auto samplerIter = mProxySamplerMap.find(name);
	if (samplerIter == mProxySamplerMap.end())
		return;
	if (samplerIter->second != sampler)
		return;
	mProxySamplerMap.erase(samplerIter);
}

void RenderProcess::AddCommandBuffer(const std::string& name, RHICommandBuffer* commandBuffer)
{
	auto commandBufferIter = mProxyCommandBufferMap.find(name);
	if (commandBufferIter != mProxyCommandBufferMap.end())
	{
		commandBufferIter->second = commandBuffer;
	}
	else
	{
		mProxyCommandBufferMap.insert({ name, commandBuffer });
	}
	commandBuffer->SetProcessAndName(this, name);
}

void RenderProcess::RemoveCommandBuffer(const std::string& name, RHICommandBuffer* commandBuffer)
{
	auto commandBufferIter = mProxyCommandBufferMap.find(name);
	if (commandBufferIter == mProxyCommandBufferMap.end())
		return;
	if (commandBufferIter->second != commandBuffer)
		return;
	mProxyCommandBufferMap.erase(commandBufferIter);
}

void RenderProcess::AddFence(const std::string& name, RHIFence* fence)
{
	auto fenceIter = mProxyFenceMap.find(name);
	if (fenceIter != mProxyFenceMap.end())
	{
		fenceIter->second = fence;
	}
	else
	{
		mProxyFenceMap.insert({ name, fence });
	}
	fence->SetProcessAndName(this, name);
}

void RenderProcess::RemoveFence(const std::string& name, RHIFence* fence)
{
	auto fenceIter = mProxyFenceMap.find(name);
	if (fenceIter == mProxyFenceMap.end())
		return;
	if (fenceIter->second != fence)
		return;
	mProxyFenceMap.erase(fenceIter);
}

void RenderProcess::AddSemaphore(const std::string& name, RHISemaphore* semaphore)
{
	auto semaphoreIter = mProxySemaphoreMap.find(name);
	if (semaphoreIter != mProxySemaphoreMap.end())
	{
		semaphoreIter->second = semaphore;
	}
	else
	{
		mProxySemaphoreMap.insert({ name, semaphore });
	}
	semaphore->SetProcessAndName(this, name);
}

void RenderProcess::RemoveSemaphore(const std::string& name, RHISemaphore* semaphore)
{
	auto semaphoreIter = mProxySemaphoreMap.find(name);
	if (semaphoreIter == mProxySemaphoreMap.end())
		return;
	if (semaphoreIter->second != semaphore)
		return;
	mProxySemaphoreMap.erase(semaphoreIter);
}

RefCountPtr<RHIBuffer> RenderProcess::GetBuffer(const std::string& process, const std::string& name) const
{
	return GetProcess(process)->GetBuffer(name);
}

RefCountPtr<RHITexture> RenderProcess::GetTexture(const std::string& process, const std::string& name) const
{
	return GetProcess(process)->GetTexture(name);
}

RefCountPtr<RHIPipeline> RenderProcess::GetPipeline(const std::string& process, const std::string& name) const
{
	return GetProcess(process)->GetPipeline(name);
}

RefCountPtr<RHIRenderPass> RenderProcess::GetRenderPass(const std::string& process, const std::string& name) const
{
	return GetProcess(process)->GetRenderPass(name);
}

RefCountPtr<RHIFrameBuffer> RenderProcess::GetFrameBuffer(const std::string& process, const std::string& name) const
{
	return GetProcess(process)->GetFrameBuffer(name);
}

RefCountPtr<RHIDescriptor> RenderProcess::GetDescriptor(const std::string& process, const std::string& name) const
{
	return GetProcess(process)->GetDescriptor(name);
}

RefCountPtr<AccelerationStructure> RenderProcess::GetAccelerationStructure(const std::string& process, const std::string& name) const
{
	return GetProcess(process)->GetAccelerationStructure(name);
}

RefCountPtr<AccelerationStructureGeometry> RenderProcess::GetAccelerationStructureGeometry(const std::string& process, const std::string& name) const
{
	return GetProcess(process)->GetAccelerationStructureGeometry(name);
}

RefCountPtr<RHISampler> RenderProcess::GetSampler(const std::string& process, const std::string& name) const
{
	return GetProcess(process)->GetSampler(name);
}

RefCountPtr<RHICommandBuffer> RenderProcess::GetCommandBuffer(const std::string& process, const std::string& name) const
{
	return GetProcess(process)->GetCommandBuffer(name);
}

RefCountPtr<RHIFence> RenderProcess::GetFence(const std::string& process, const std::string& name) const
{
	return GetProcess(process)->GetFence(name);
}

RefCountPtr<RHISemaphore> RenderProcess::GetSemaphore(const std::string& process, const std::string& name) const
{
	return GetProcess(process)->GetSemaphore(name);
}

RenderProcess* RenderProcess::GetProcess(const std::string& name) const
{
	return GRenderState->mRenderProcessMap[GetFactIndex(name)];
}

const uint32 RenderProcess::GetFactIndex(const std::string& name) const
{
	if (name == FIRST_PROCESS)
	{
		return 0;
	}
	else if (name == LAST_PROCESS)
	{
		return GRenderState->mRenderProcessMap.size() - 1;
	}
	else
	{
		uint32 selfIndex = UINT32_MAX;
		for (uint32 i = 0; i < GRenderState->mRenderProcessMap.size(); ++i)
		{
			if (GRenderState->mRenderProcessMap[i] == this)
			{
				selfIndex = i;
			}
			if (GRenderState->mRenderProcessMap[i]->GetName() == name)
			{
				return i;
			}
		}

		if (name == PREV_PROCESS)
		{
			assert(selfIndex != UINT32_MAX && selfIndex != 0);
			return selfIndex - 1;
		}
		else if (name == NEXT_PROCESS)
		{
			assert(selfIndex != UINT32_MAX && selfIndex != GRenderState->mRenderProcessMap.size() - 1);
			return selfIndex + 1;
		}
		// No match process
		assert(0);
	}
	assert(0);
	return UINT32_MAX;
}

void RenderProcess::Init(GameScene* gameScene)
{
	mGameScene = gameScene;
}
